#pragma once

#include<pthread.h>
#include<vector>
#include<ext/hash_map>
#include<ext/hash_set>
#include<stdint.h>
#include "lars_reactor.h"
#include "lars.pb.h"
#include "dns_route.h"

//定义订阅列表数据关系类型，key->modid/cmdid， value->fds(订阅的客户端文件描述符)
typedef __gnu_cxx::hash_map<uint64_t, __gnu_cxx::hash_set<int>> subscribe_map;

//定义发布列表的数据关系类型, key->fd(订阅客户端的文件描述符), value->modids
typedef __gnu_cxx::hash_map<int, __gnu_cxx::hash_set<uint64_t>> publish_map;

// 设置成单例模式
class SubscribeList{
public:
    //初始化单例对象
    static void init(){
        _instance = new SubscribeList();
    }
    //获取单例方法
    static SubscribeList* instance(){
        //保证init方法在这个进程执行中 只被执行一次
        pthread_once(&_once, init);
        return _instance;
    }

    // 订阅
    void subscribe(uint64_t mod, int fd);

    // 取消订阅
    void unsubscribe(uint64_t mod, int fd);
    
    // 发布，输入形参:是那些modid被修改了，被修改的模块所对应的fd应该被发布
    void publish(std::vector<uint64_t> &change_mods);

    //根据在线用户fd得到需要发布的列表
    void make_publish_map(listen_fd_set &online_fds, publish_map &need_publish);

    // 获取_push_list数据
    publish_map get_push_list(){
        return _push_list;
    }

private:
    // 全部构造函数私有化，构成单例模式
    SubscribeList();
    SubscribeList(const SubscribeList&);
    const SubscribeList& operator=(const SubscribeList&);

    // 指向当前单例对象的指针
    static SubscribeList* _instance;
    //用于保证创建单例的init方法只执行一次的锁
    static pthread_once_t _once;

    // 订阅清单
    subscribe_map _book_list;
    // 订阅清单对应的锁
    pthread_mutex_t _book_list_lock;

    // 发布清单
    publish_map _push_list;
    // 发布清单对应的锁
    pthread_mutex_t _push_list_lock;

};